﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TvdP
{
    [TestClass]
    public partial class AdaptersUnitTest
    {
        [TestClass]
        public class AdapterComparerUnitTest
        {
            class Class1 { }
            class Class2 { }
            class Class3 { }
            class Class4 { }
            class Class5 { }

            [TestMethod]
            public void Compare_places_delegate_with_more_parameters_before_delegate_with_fewer_parameters()
            {
                var dgt1 = new Func<Class1, Class5>(c1 => null);
                var dgt2 = new Func<Class1, Class2, Class5>((c1, c2) => null);
                var dgt4 = new Func<Class1, Class2, Class3, Class4, Class5>((c1, c2, c3, c4) => null);

                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt2) > 0, "Delegate with 1 parameter not placed after delegate with 2 parameters");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt4) > 0, "Delegate with 1 parameter not placed after delegate with 4 parameters");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt2, dgt1) < 0, "Delegate with 2 parameters not placed before delegate with 1 parameter");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt2, dgt4) > 0, "Delegate with 2 parameters not placed after delegate with 4 parameters");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt4, dgt1) < 0, "Delegate with 4 parameters not placed before delegate with 1 parameter");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt4, dgt2) < 0, "Delegate with 4 parameters not placed before delegate with 2 parameters");
            }

            [TestMethod]
            public void Compare_returns_0_when_comparing_delegates_with_equal_signature()
            {
                var dgt1 = new Func<Class1, Class5>(c1 => null);
                var dgt2 = new Func<Class1, Class5>(c1 => null);
                var dgt3 = new Func<Class1, Class2, Class3, Class4, Class5>((c1, c2, c3, c4) => null);
                var dgt4 = new Func<Class1, Class2, Class3, Class4, Class5>((c1, c2, c3, c4) => null);

                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt2) == 0, "Compare on different delegate objects with equal signatures does not return 0.");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt3, dgt4) == 0, "Compare on different delegate objects with equal signatures does not return 0.");
            }

            [TestMethod]
            public void Compare_returns_0_when_comparing_delegate_instance_with_itself()
            {
                var dgt1 = new Func<Class1, Class5>(c1 => null);
                var dgt3 = new Func<Class1, Class2, Class3, Class4, Class5>((c1, c2, c3, c4) => null);

                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt1) == 0, "Compare on same delegate object instance does not return 0.");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt3, dgt3) == 0, "Compare on same delegate object instance does not return 0.");
            }

            class ClassB { }
            class ClassAB : ClassB { }
            interface IX { }

            [TestMethod]
            public void Compare_places_delegate_with_parameter_with_most_derived_class_type_first_when_delegates_have_1_parameter()
            {
                var dgt1 = new Func<ClassB, Class5>(b => null);
                var dgt2 = new Func<ClassAB, Class5>(ab => null);

                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt2) > 0, "Compare does not place delegate with parameter of most derived type first when comparing delegate with 1 parameter.");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt2, dgt1) < 0, "Compare does not place delegate with parameter of most derived type first when comparing delegate with 1 parameter.");
            }

            [TestMethod]
            public void Compare_ignores_parameter_type_hierarchy_when_comparing_delegates_with_multiple_parameters()
            {
                var dgt1 = new Func<ClassB, ClassB, Class5>((b1, b2) => null);
                var dgt2 = new Func<ClassAB, ClassAB, Class5>((ab1, ab2) => null);

                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt2) == 0, "Compare does not ignore type hierarchy when comparing delegates with multiple parameters.");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt2, dgt1) == 0, "Compare does not ignore type hierarchy when comparing delegates with multiple parameters.");
            }

            [TestMethod]
            public void Compare_places_delegate_with_parameter_of_interface_type_first_when_delegates_have_1_parameter()
            {
                var dgt1 = new Func<ClassB, Class5>(b => null);
                var dgt2 = new Func<IX, Class5>(x => null);

                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt2) > 0, "Compare does not place delegate with parameter of interface type first when comparing delegate with 1 parameter.");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt2, dgt1) < 0, "Compare does not place delegate with parameter of interface type first when comparing delegate with 1 parameter.");
            }

            [TestMethod]
            public void Compare_ignores_parameter_type_interface_attribute_when_comparing_delegates_with_multiple_parameters()
            {
                var dgt1 = new Func<IX, IX, Class5>((x1, x2) => null);
                var dgt2 = new Func<ClassAB, ClassAB, Class5>((ab1, ab2) => null);

                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt1, dgt2) == 0, "Compare does not ignore type interface attribute when comparing delegates with multiple parameters.");
                Assert.IsTrue(Adapters.AdapterComparer._Instance.Compare(dgt2, dgt1) == 0, "Compare does not ignore type interface attribute when comparing delegates with multiple parameters.");
            }
        
        }
    }
}
